package infra.starters;


import java.util.Vector;

import processing.core.*;

import org.NooLab.utilities.logging.LogControl;
import org.NooLab.utilities.logging.PrintLog;

import org.NooLab.compare.utilities.math.DistanceControlProperties;
import org.NooLab.glue.components.pkg.TaskPackage;
import org.NooLab.glue.instances.*;
import org.NooLab.glue.interfaces.*;
import org.NooLab.glue.subscription.*;

 
import infra.common.DataContainer;
 
 

public class SourceInstanceSimpleSubscr extends 
										  			PApplet
										implements
										 			ResultDeliveryIntf{
	
	private static final long serialVersionUID = -6009042607634506822L;

	
	SrcInstanceSimpleSubscribe srcInstance;
	 
	
	public void setup(){
		 
		
		background( 188,208,188);
		// start this in its own thread...
		srcInstance = new SrcInstanceSimpleSubscribe( (ResultDeliveryIntf)this );
		
		// use LogControl to control output of log messages
		LogControl.globeScope = 2; // 1=local definitions  default = 2
		LogControl.Level = 2 ;

	}
	
	
	
	public void draw(){
		 
	}
 
	public void resultsToAppletContext(String dataStr){
		println(dataStr);
	}


	public void keyPressed() {
		 
		if (key=='s'){
			
			srcInstance.prepareData().send() ;
		}
		
		if (key=='f'){
			srcInstance.prepareSubscriptions() ;
		}
		
		if (key=='r'){
			srcInstance.reconnect() ;
		}
		 
		if ((key=='q') || (key=='d')){
			srcInstance.cancelTask() ;
		}
		
		if (key=='x'){
			if (srcInstance!=null){
				srcInstance.disconnect();
			}
			System.exit(0);
		}
	}
}

// ============================================================================


/**
 * this is an example class demonstrating the use of the client-API for NooLabGlue 
 */
class SrcInstanceSimpleSubscribe implements Runnable, ResultReceiverIntf{ 

	// 
	ParticipantFactory factory ;
	ParticipantSourceIntf participant ;
	 
	ResultDeliveryIntf parent;
	
	// helper objects
	Thread iThrd; 
	PrintLog out = new PrintLog(2,false);
	
	
	public SrcInstanceSimpleSubscribe( ResultDeliveryIntf parent ){
		this.parent = parent;
		// we start the instance into a thread, which is independent from the PApplet-process
		(new Thread(this,"SrcInstance-main")).start() ;
	}	 
		
	public void run() {
		// we use simple threading just to become independent from the applet
		create();
	}

	private void create(){
		 
		
		try{
			// note that in order to receive any messages, you have to implement
			// the interface: "ResultReceiverIntf"
			// just 2 lines to enable messaging for a client: (1) defining the factory, (2) connecting 
			// note, that the properties are taken from the file "glue.properties", which is expected at the provided path 
			factory = new ParticipantFactory( "D:/dev/java/data/test/mb/properties/source" , this ) ;
			
			
			// remove remote address as defined in file "glue.properties", switch to local MessageBoard 
			// factory.getFactoryProperties().setHostAddressName("", 7070) ;
			
			// create the client and connect to the message board
			participant = (ParticipantSourceIntf)factory.connect() ;
			// now we can send messages into our probabilistic glue network ! 
// TODO: for unique instances, we have to send an unregister before registering !! 
			// there could be a "cut of the wires", i.e. the MB is left uninformed, we have to reregister, but
			// the old registration is still living
			// -> unregistering needs the FULL name to be checked on the side of the MessageBoard !!!
			
			// optional for advanced stuff
			prepareSubscriptions() ;
			
		
		}catch(Exception e){
			e.printStackTrace();
		}
		
	}
	  

	// =============== local methods : the use-layer ===============

	public SrcInstanceSimpleSubscribe prepareData(){

		TaskPackage taskPackage;
		
		
		String filename, contentType = "rawdata";

		contentType = "doc" ;
		DataContainer dataobj=new DataContainer() ;
		
		// creating a TaskPackage
		taskPackage = factory.getTaskPackage( contentType ) ;
		// note, that in case of UDP ONLY references should be transmitted,
		// UDP may cut large messages dependent on the settings/capabilities of the hardware router !!!
		// for large data sets to be included in the taskpackage use TCP
		
		filename = "D:/dev/java/data/texter/data/out/textmapdata_00007.txt"+" - 123";
		
		// the taskPackage may contain ANY kind of object, ...there are slots for primitive types
		taskPackage.getNums().add(99 ) ;
		taskPackage.setDataString( filename) ;
		
		// any user-based object format, of course, 
		dataobj.setObjFromFile(filename) ; // e.g. reading the file and representing it as byte[]
		// note, that in case of UDP ONLY references should be transmitted, 
		// no objects should be used, since it is not predictable, if and where the (physical) router
		// will truncate the message
		taskPackage.setData(dataobj, "dataobj");
		
		taskPackage.setTypeOfProceedings("task"); // task = expressing expectation of some kind of result
		 							  // "travel" = one way pass through, no results will be returned
									  // "result" = the package returned to the SOURCE !
		
		
		participant.setTask(taskPackage);
		
		return this;
	}
	
	 
	public SrcInstanceSimpleSubscribe send(){
		
		// 3 = a parameter that influences the topology of routing the message to
		//     cascaded MessageBoards, the value describes the maximum number of hops   
		participant.send(3);  
		
		return this;
	}

	// =============== interfaced methods ===============
	
	// finally, here we will find the results ... 
	// TODO: the client should buffer it upon request, 
	//       such that an application client can get them all at once, or
	//       based on a trigger
	
	
	@Override
	public void resultsProvider(TaskPackage resultpackage) {
		DataContainer dc;
		long tid ;
		String str, commentaryStr;
		
		out.print(3, "\n\rMsgSourceInstance :: SrcInstance :: resultsProvider()");
		
		tid = resultpackage.getTransactionID();
		
		commentaryStr = resultpackage.getDataString();
		
	 
		// of course, the RECEPTOR should have put a string into it
		// infra.common.DataContainer
		Object obj = resultpackage.getDataObj();
		dc = (DataContainer)obj ;
		str = (String)dc.getObjData();
		
		out.printErr(1, "\r\nResults for transaction id="+tid+", content : "+str +" ,  experiences : "+ commentaryStr+"\n");
		
		parent.resultsToAppletContext(str) ;
	}

	@Override
	public void currentStateMessage(String str) {
		
		out.printErr(4, "MsgSourceInstance :: SrcInstance :: currentStateMessage()");
		out.print(2,"Simple State Message : "+str);
		
	}

	 
	// =============== wrapped methods ===============

	public void cancelTask(){
		int cancelState=0;
		/*
		 *    canceling a task needs a transactionID,
		 *    if none is given, the last activated one will be chosen 
		 *    (acc. to option in factoryProperties, factory.config() ) 
		 */
		
		if (participant!=null){
			cancelState = participant.cancelTask();
		}
		
		if (cancelState<0){
			// failure of canceling ;
		}
	}
	
	public void reconnect(){
		if (participant!=null){
			participant.connect();
		}
	}
	
	public void disconnect(){
		if (participant!=null){
			participant.disconnect() ;
		}
	}

	// =============== advanced methods ==============

	// this is the frontend label for dealing with subscriptions
	public void prepareSubscriptions(){
		FuturesIntf futures;
		
		futures = participant.getFutures();
		
		issueSimpleSubscription(futures) ;
		  
	}
	
  
	private void issueSimpleSubscription( FuturesIntf futures ){
		String subguid;
		int r;
		DistanceControlProperties distanceCtrl=new DistanceControlProperties();
		/*
		 * Subscriptions are organized in a collection called "Futures";
		 * use the Futures-object to create a new instance of a subscription...
		 */
		FutureIntf subscription = futures.create(distanceCtrl);
		
		// create a simple filter using label and criteria for defining the comparison 
		// a simple subscription consists of: 
		//                 a method label  // a set of values to consider // a set of excluding values // a matching requirement   
		subscription.addProperty( "keywords", (new String[]{"a","b","c","d"}), (new String[]{"x"}), 0.7) ;
		subguid = futures.add( subscription ); 
 
												out.print(2, "going to publish the subscription... ");
		r = futures.publish( subguid );
		// note that publishing a subscription will not be a transaction, 
		// hence no confirmation will be returned
		
			if (r<0){
				out.print(2, "publishing the simple subscription failed! (r="+r+")");
			}else{
				out.print(2, "simple subscription "+subguid+" has been published.");
			}
		
	}

	@Override
	public void resultsProvider(Vector<TaskPackage> resultpackages) {
		// TODO Auto-generated method stub
		
	}
	
 
	
}
 
  
 
